﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Admin.NET.Core;
using Admin.NET.Core.Service;
using Microsoft.AspNetCore.Http;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Admin.NET.Application.Entity;
namespace Admin.NET.Application;

/// <summary>
/// 审批流程服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupNameStore, Order = 100)]
public partial class StoreProcessFlowStepService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<StoreProcessFlowStep> _storeProcessFlowStepRep;
    private readonly SqlSugarRepository<StoreProcessRecord> _storeProcessRecordRep;
    private readonly SqlSugarRepository<StoreInbound> _storeInboundRep;
    private readonly SqlSugarRepository<StoreOutbound> _storeOutboundRep;
    private readonly SqlSugarRepository<StoreMaterials> _storeMaterialsRep;
    private readonly SqlSugarRepository<SysUser> _sysUserRep;
    private readonly SqlSugarRepository<SysRole> _sysRoleRep;
    private readonly SqlSugarRepository<SysUserRole> _sysUserRoleRep;
    private readonly ISqlSugarClient _sqlSugarClient;
    private readonly StoreMaterialsService _storeMaterialsService;
    private readonly UserManager _userManager;

    public StoreProcessFlowStepService(
        SqlSugarRepository<StoreProcessFlowStep> storeProcessFlowStepRep,
        SqlSugarRepository<StoreProcessRecord> storeProcessRecordRep,
        SqlSugarRepository<StoreInbound> storeInboundRep,
        SqlSugarRepository<StoreOutbound> storeOutboundRep,
        SqlSugarRepository<StoreMaterials> storeMaterialsRep,
        SqlSugarRepository<SysUser> sysUserRep,
        SqlSugarRepository<SysRole> sysRoleRep,
        SqlSugarRepository<SysUserRole> sysUserRoleRep,
        ISqlSugarClient sqlSugarClient,
        StoreMaterialsService storeMaterialsService,
        UserManager userManager)
    {
        _storeProcessFlowStepRep = storeProcessFlowStepRep;
        _storeProcessRecordRep = storeProcessRecordRep;
        _storeInboundRep = storeInboundRep;
        _storeOutboundRep = storeOutboundRep;
        _storeMaterialsRep = storeMaterialsRep;
        _sysUserRep = sysUserRep;
        _sysRoleRep = sysRoleRep;
        _sysUserRoleRep = sysUserRoleRep;
        _sqlSugarClient = sqlSugarClient;
        _storeMaterialsService = storeMaterialsService;
        _userManager = userManager;
    }

    /// <summary>
    /// 分页查询审批流程 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询审批流程")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<StoreProcessFlowStepOutput>> Page(PageStoreProcessFlowStepInput input)
    {
        input.Keyword = input.Keyword?.Trim();

        // 如果指定了分类ID，获取该分类及其所有下级分类的ID列表
        List<long> categoryIds = new List<long>();
        if (input.StoreTypeId != null && input.StoreTypeId > 0)
        {
            categoryIds = await GetCategoryAndChildrenIds(input.StoreTypeId.Value);
        }

        // 如果指定了机构ID，获取该机构及其所有下级机构的ID列表
        List<long> orgIds = new List<long>();
        if (input.OrgId != null && input.OrgId.Value > 0)
        {
            orgIds = await GetOrgAndChildrenIds(input.OrgId.Value);
        }

        var loginUserId = _userManager.UserId;
        var isSystemAdmin = await IsSystemAdminAsync(loginUserId);
        var roleCodes = await GetUserRoleCodesAsync(loginUserId);
        var canManageAllSteps = isSystemAdmin || roleCodes.Contains(RoleCodes.StoreManager);
        var flowDefinitions = BuildFlowDefinitions();

        var query = _storeProcessFlowStepRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.FlowType.Contains(input.Keyword) || u.BatchNo.Contains(input.Keyword) || u.RequestNo.Contains(input.Keyword) || u.StoreTypeName.Contains(input.Keyword) || u.MaterialName.Contains(input.Keyword) || u.Unit.Contains(input.Keyword) || u.ApplicantName.Contains(input.Keyword) || u.ApplicantDept.Contains(input.Keyword) || u.ReceiverName.Contains(input.Keyword) || u.ReceiverDept.Contains(input.Keyword) || u.Remark.Contains(input.Keyword) || u.ConfirmerName.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.FlowType), u => u.FlowType.Contains(input.FlowType.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.BatchNo), u => u.BatchNo.Contains(input.BatchNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.RequestNo), u => u.RequestNo.Contains(input.RequestNo.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.StoreTypeName), u => u.StoreTypeName.Contains(input.StoreTypeName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialName), u => u.MaterialName.Contains(input.MaterialName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Unit), u => u.Unit.Contains(input.Unit.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplicantName), u => u.ApplicantName.Contains(input.ApplicantName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ApplicantDept), u => u.ApplicantDept.Contains(input.ApplicantDept.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ReceiverName), u => u.ReceiverName.Contains(input.ReceiverName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ReceiverDept), u => u.ReceiverDept.Contains(input.ReceiverDept.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), u => u.Remark.Contains(input.Remark.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.ConfirmerName), u => u.ConfirmerName.Contains(input.ConfirmerName.Trim()))
            .WhereIF(input.StoreTypeId != null && input.StoreTypeId > 0, u => categoryIds.Contains((long)u.StoreTypeId))
            .WhereIF(input.MaterialId != null, u => u.MaterialId == input.MaterialId)
            .WhereIF(input.ApplicantId != null, u => u.ApplicantId == input.ApplicantId)
            .WhereIF(input.ReceiverId != null, u => u.ReceiverId == input.ReceiverId)
            .WhereIF(input.RequestTimeRange?.Length == 2, u => u.RequestTime >= input.RequestTimeRange[0] && u.RequestTime <= input.RequestTimeRange[1])
            .WhereIF(input.ExpectedDateRange?.Length == 2, u => u.ExpectedDate >= input.ExpectedDateRange[0] && u.ExpectedDate <= input.ExpectedDateRange[1])
            .WhereIF(input.CompletedTimeRange?.Length == 2, u => u.CompletedTime >= input.CompletedTimeRange[0] && u.CompletedTime <= input.CompletedTimeRange[1])
            .WhereIF(input.StatusNewOrChange.HasValue, u => u.StatusNewOrChange == input.StatusNewOrChange)
            .WhereIF(input.ApprovalAction.HasValue, u => u.ApprovalAction == input.ApprovalAction)
            .WhereIF(input.ConfirmerId != null, u => u.ConfirmerId == input.ConfirmerId)
            .WhereIF(input.OrgId != null && input.OrgId.Value > 0, u => orgIds.Contains((long)u.OrgId))
            .WhereIF(!input.IncludeArchived && !input.ApprovalAction.HasValue, u => u.ApprovalAction != StatusApprovalEnum.Completed && u.ApprovalAction != StatusApprovalEnum.Rejected)
            .Select<StoreProcessFlowStepOutput>();

        if (input.CurrentUserId.HasValue)
        {
            var currentUserId = input.CurrentUserId.Value;
            if (input.MyApprovalHistory)
            {
                query = query.Where(u => u.ConfirmerId == currentUserId && (u.ApprovalAction == StatusApprovalEnum.Completed || u.ApprovalAction == StatusApprovalEnum.Rejected));
            }
            else
            {
                query = query.Where(u => u.ConfirmerId == currentUserId && u.ApprovalAction != StatusApprovalEnum.Completed && u.ApprovalAction != StatusApprovalEnum.Rejected);
            }
        }
        var pagedResult = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);

        // 优化: 批量构建分类路径 (防止N+1查询) ⚡
        var typeIds = pagedResult.Items
            .Where(x => x.StoreTypeId.HasValue)
            .Select(x => x.StoreTypeId.Value)
            .Distinct()
            .ToList();

        var typePaths = typeIds.Count > 0
            ? await _storeMaterialsService.BatchBuildCategoryPathsAsync(typeIds)
            : new Dictionary<long, string>();

        // 在内存中关联数据
        foreach (var item in pagedResult.Items)
        {
            if (item.StoreTypeId.HasValue && typePaths.ContainsKey(item.StoreTypeId.Value))
            {
                item.StoreTypeDisplayName = typePaths[item.StoreTypeId.Value];
            }

            PopulateFlowRuntimeMetadata(item, loginUserId, isSystemAdmin, canManageAllSteps, flowDefinitions);
        }

        return pagedResult;
    }

    /// <summary>
    /// 获取审批流程详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取审批流程详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<StoreProcessFlowStepOutput> Detail([FromQuery] QueryByIdStoreProcessFlowStepInput input)
    {
        var entity = await _storeProcessFlowStepRep.GetFirstAsync(u => u.Id == input.Id);
        var output = entity.Adapt<StoreProcessFlowStepOutput>();

        // 填充物资分类的完整路径显示名称
        if (entity.StoreTypeId.HasValue)
        {
            var typePaths = await _storeMaterialsService.BatchBuildCategoryPathsAsync(new List<long> { entity.StoreTypeId.Value });
            if (typePaths.ContainsKey(entity.StoreTypeId.Value))
            {
                output.StoreTypeDisplayName = typePaths[entity.StoreTypeId.Value];
            }
        }

        var flowDefinitions = BuildFlowDefinitions();
        var loginUserId = _userManager.UserId;
        var isSystemAdmin = await IsSystemAdminAsync(loginUserId);
        var roleCodes = await GetUserRoleCodesAsync(loginUserId);
        var canManageAllSteps = isSystemAdmin || roleCodes.Contains(RoleCodes.StoreManager);
        PopulateFlowRuntimeMetadata(output, loginUserId, isSystemAdmin, canManageAllSteps, flowDefinitions);

        return output;
    }

    /// <summary>
    /// 增加审批流程 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加审批流程")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddStoreProcessFlowStepInput input)
    {
        var entity = input.Adapt<StoreProcessFlowStep>();
        
        var flowDefinitions = BuildFlowDefinitions();
        var definition = ResolveFlowDefinition(flowDefinitions, entity.FlowType);
        entity.TotalSteps = definition.TotalSteps;
        
        // 如果提供了确认人ID，自动查询并填充确认人姓名
        if (entity.ConfirmerId.HasValue && entity.ConfirmerId.Value > 0)
        {
            var confirmer = await _sqlSugarClient.Queryable<SysUser>()
                .ClearFilter() // 清除所有过滤器（如租户过滤、软删除过滤等）
                .Where(u => u.Id == entity.ConfirmerId.Value)
                .FirstAsync();
                
            if (confirmer != null)
            {
                entity.ConfirmerName = confirmer.RealName;
            }
        }
        
        return await _storeProcessFlowStepRep.InsertAsync(entity) ? entity.Id : 0;
    }

    /// <summary>
    /// 更新审批流程 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新审批流程")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateStoreProcessFlowStepInput input)
    {
        // 使用事务确保数据一致性
        await _sqlSugarClient.Ado.UseTranAsync(async () =>
        {
            // 获取原始实体
            var originalEntity = await _storeProcessFlowStepRep.GetFirstAsync(u => u.Id == input.Id);
            if (originalEntity == null)
                throw Oops.Oh(ErrorCodeEnum.D1002);

            var flowDefinitions = BuildFlowDefinitions();
            var definition = ResolveFlowDefinition(flowDefinitions, originalEntity.FlowType);
            var currentStage = definition.GetStage(originalEntity.CurrentStep);

            var isSystemAdmin = await IsSystemAdminAsync(_userManager.UserId);
            input.AdminDirectApprove = input.AdminDirectApprove == true
                && isSystemAdmin
                && string.Equals(input.FlowType, "出库", StringComparison.Ordinal);

            // 转换输入数据，但保留原始的框架字段
            var entity = input.Adapt<StoreProcessFlowStep>();
            entity.TotalSteps = definition.TotalSteps;
            entity.CurrentStep = originalEntity.CurrentStep;

            var isExecutionStage = currentStage.IsExecutionStage;

            // 判断是否存在ConfirmerId
            // 如果前端已经明确指定了确认人，则优先使用前端的选择
            // 否则根据当前登录账号的ID，获取直属主管Id和直属主管姓名
            if (input.ConfirmerId.HasValue && input.ConfirmerId.Value > 0)
            {
                // 前端已指定确认人，使用前端的选择并验证该用户是否存在
                var specifiedUser = await _sysUserRep.AsQueryable()
                    .ClearFilter()
                    .Where(u => u.Id == input.ConfirmerId.Value && u.Status == StatusEnum.Enable)
                    .FirstAsync();
                if (specifiedUser != null)
                {
                    entity.ConfirmerId = specifiedUser.Id;
                    entity.ConfirmerName = specifiedUser.RealName;
                }
                else
                {
                    // 指定的确认人无效，回退到自动分配逻辑
                    await AssignDefaultConfirmer(entity);
                }
            }
            else if (!entity.ConfirmerId.HasValue || entity.ConfirmerId.Value <= 0)
            {
                if (isExecutionStage)
                {
                    AssignExecutionConfirmer(entity);
                }
                else
                {
                    // 没有指定确认人，使用自动分配逻辑
                    await AssignDefaultConfirmer(entity);
                }
            }
            else
            {
                // entity已有确认人ID，验证并补充确认人姓名
                var existingUser = await _sysUserRep.AsQueryable()
                    .ClearFilter()
                    .Where(u => u.Id == entity.ConfirmerId.Value && u.Status == StatusEnum.Enable)
                    .FirstAsync();
                if (existingUser != null)
                {
                    entity.ConfirmerName = existingUser.RealName;
                }
                else
                {
                    if (isExecutionStage)
                    {
                        // 执行阶段默认当前操作人作为确认人
                        AssignExecutionConfirmer(entity);
                    }
                    else
                    {
                        // 现有确认人无效，回退到自动分配逻辑
                        await AssignDefaultConfirmer(entity);
                    }
                }
            }


            // 保留原始实体的重要框架字段，防止数据隔离被破坏
            entity.Id = originalEntity.Id;
            entity.TenantId = originalEntity.TenantId;
            entity.OrgId = originalEntity.OrgId;
            entity.CreateTime = originalEntity.CreateTime;
            entity.CreateUserId = originalEntity.CreateUserId;
            entity.CreateUserName = originalEntity.CreateUserName;
            entity.IsDelete = originalEntity.IsDelete;

            // 保障物资金额与数量一致
            var effectivePrice = entity.MaterialPrice ?? originalEntity.MaterialPrice;
            entity.MaterialPrice = effectivePrice ?? originalEntity.MaterialPrice;
            if (entity.Quantity.HasValue && effectivePrice.HasValue)
            {
                entity.MaterialPriceTotal = Math.Round(entity.Quantity.Value * effectivePrice.Value, 2);
            }
            else
            {
                entity.Quantity ??= originalEntity.Quantity;
                entity.MaterialPriceTotal ??= originalEntity.MaterialPriceTotal;
            }
            
            var currentTime = DateTime.Now;

            // 根据当前步骤处理审批逻辑
            await ProcessApprovalStep(entity, originalEntity, input, currentTime, definition);

            // 更新实体 - 只更新业务字段，忽略框架字段
            // 并发保护：仅当当前数据库中的状态仍等于读取到的原始状态时才更新，避免连点造成状态越级
            var affected = await _storeProcessFlowStepRep.AsUpdateable(entity)
                // .IgnoreColumns(...) // 需要时可恢复忽略框架字段
                .Where(it => it.Id == entity.Id && it.ApprovalAction == originalEntity.ApprovalAction)
                .ExecuteCommandAsync();

            if (affected == 0)
            {
                // 没有任何记录被更新，说明状态已被其他请求修改，提示前端刷新重试
                throw Oops.Oh("审批状态已发生变化，请刷新后重试");
            }

            // 创建审批记录
            await CreateProcessRecord(entity, originalEntity.ApprovalAction, input.AdminDirectApprove == true);
        });
    }

    /// <summary>
    /// 退回审批流程 ↩️
    /// </summary>
    [DisplayName("退回审批流程")]
    [ApiDescriptionSettings(Name = "ReturnPreviousStep"), HttpPost]
    public async Task ReturnPreviousStep(ReturnStoreProcessFlowStepInput input)
    {
        await _sqlSugarClient.Ado.UseTranAsync(async () =>
        {
            var entity = await _storeProcessFlowStepRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);

            if (entity.ApprovalAction == StatusApprovalEnum.Completed)
            {
                throw Oops.Oh("发放完成后无法退回审批流程");
            }

            if (entity.ApprovalAction == StatusApprovalEnum.Rejected)
            {
                throw Oops.Oh("已拒绝的审批流程无法退回");
            }

            if (entity.CurrentStep <= 1)
            {
                throw Oops.Oh("当前已处于首个步骤，无法退回");
            }

            var (targetStep, targetStatus) = ResolvePreviousStep(entity);
            var originalStatus = entity.ApprovalAction;

            entity.CurrentStep = targetStep;
            entity.ApprovalAction = targetStatus;
            entity.CompletedTime = null;

            var (confirmerId, confirmerName) = await ResolveReturnConfirmerAsync(entity, targetStatus);
            entity.ConfirmerId = confirmerId;
            entity.ConfirmerName = confirmerName;

            await _storeProcessFlowStepRep.AsUpdateable()
                .SetColumns(it => new StoreProcessFlowStep
                {
                    CurrentStep = entity.CurrentStep,
                    ApprovalAction = entity.ApprovalAction,
                    ConfirmerId = entity.ConfirmerId,
                    ConfirmerName = entity.ConfirmerName,
                    CompletedTime = entity.CompletedTime
                })
                .Where(it => it.Id == entity.Id)
                .ExecuteCommandAsync();

            await SyncRequestStatusAsync(entity);

            var remark = BuildReturnRemark(originalStatus, targetStatus, input.Reason);
            await CreateProcessRecord(entity, originalStatus, false, remark);
        });
    }

    /// <summary>
    /// 处理审批步骤逻辑（统一由状态机驱动）
    /// </summary>
    private async Task ProcessApprovalStep(StoreProcessFlowStep entity, StoreProcessFlowStep originalEntity, UpdateStoreProcessFlowStepInput input, DateTime currentTime, FlowDefinition definition)
    {
        var currentStage = definition.GetStage(originalEntity.CurrentStep);
        var adminDirectApprove = input.AdminDirectApprove == true;

        if (input.ApprovalAction == StatusApprovalEnum.Rejected)
        {
            entity.ApprovalAction = StatusApprovalEnum.Rejected;
            entity.CompletedTime = currentTime;
            
            await HandleRejectionInventoryRollback(entity);
            return;
        }

        if (currentStage.RequiresConfirmer && (!entity.ConfirmerId.HasValue || entity.ConfirmerId.Value <= 0))
        {
            throw Oops.Oh("审批阶段必须指定确认人，无法完成审批操作");
        }

        var targetStage = definition.GetNextStage(currentStage.Step, adminDirectApprove);
        if (targetStage == null)
        {
            throw Oops.Oh("当前流程没有可推进的下一步");
        }

        if (adminDirectApprove && targetStage.RequiresConfirmer && (!entity.ConfirmerId.HasValue || entity.ConfirmerId.Value <= 0))
        {
            throw Oops.Oh("直接审批时必须指定发放确认人");
        }

        if (adminDirectApprove)
        {
            var finalStage = definition.GetFinalStage();
            entity.CurrentStep = finalStage.Step;
            entity.ApprovalAction = finalStage.Status;
            entity.CompletedTime = currentTime;
        }
        else
        {
            entity.CurrentStep = targetStage.Step;
            entity.ApprovalAction = targetStage.Status;
            entity.CompletedTime = targetStage.IsCompletion ? currentTime : null;
        }

        if (entity.ApprovalAction == StatusApprovalEnum.Completed)
        {
            if (entity.FlowType == "入库")
            {
                await HandleInboundCompletion(entity);
            }
            else if (entity.FlowType == "出库")
            {
                await HandleOutboundCompletion(entity);
            }
        }
    }

    /// <summary>
    /// 根据用户ID获取其直属主管信息
    /// </summary>
    private async Task<(long? managerId, string? managerName)> GetDirectManagerAsync(long userId)
    {
        try
        {
            var user = await _sysUserRep.GetFirstAsync(u => u.Id == userId);
            if (user?.ManagerUserId != null)
            {
                var manager = await _sysUserRep.GetFirstAsync(u => u.Id == user.ManagerUserId);
                return (manager?.Id, manager?.RealName);
            }
            return (null, null);
        }
        catch (Exception)
        {
            return (null, null);
        }
    }

    /// <summary>
    /// 获取物资部门总管ID（通过当前确认人的直属主管）
    /// </summary>
    private async Task<long?> GetDepartmentManagerId(long currentConfirmerId)
    {
        var (managerId, _) = await GetDirectManagerAsync(currentConfirmerId);
        return managerId;
    }

    /// <summary>
    /// 获取物资部门总管姓名（通过当前确认人的直属主管）
    /// </summary>
    private async Task<string?> GetDepartmentManagerName(long currentConfirmerId)
    {
        var (_, managerName) = await GetDirectManagerAsync(currentConfirmerId);
        return managerName;
    }

    /// <summary>
    /// 根据角色名称获取用户信息
    /// </summary>
    private async Task<(long? userId, string? userName)> GetUserByRoleNameAsync(string roleName)
    {
        try
        {
            // 查找角色
            var role = await _sysRoleRep.GetFirstAsync(r => r.Name == roleName);
            if (role == null) return (null, null);

            // 查找具有该角色的用户（取第一个）
            var userRole = await _sysUserRoleRep.GetFirstAsync(ur => ur.RoleId == role.Id);
            if (userRole == null) return (null, null);

            // 获取用户信息
            var user = await _sysUserRep.GetFirstAsync(u => u.Id == userRole.UserId);
            return (user?.Id, user?.RealName);
        }
        catch (Exception)
        {
            return (null, null);
        }
    }

    /// <summary>
    /// 获取物资仓储管理人员ID（通过角色名称查询）
    /// </summary>
    private async Task<long?> GetWarehouseManagerId()
    {
        var (userId, _) = await GetUserByRoleNameAsync("物资仓储管理");
        return userId;
    }

    /// <summary>
    /// 获取物资仓储管理人员姓名
    /// </summary>
    private async Task<string?> GetWarehouseManagerName()
    {
        var (_, userName) = await GetUserByRoleNameAsync("物资仓储管理");
        return userName ?? "物资仓储管理"; // fallback到角色名称
    }

    /// <summary>
    /// 获取物资仓储人员ID（通过角色名称查询）
    /// </summary>
    private async Task<long?> GetWarehouseStaffId()
    {
        var (userId, _) = await GetUserByRoleNameAsync("物资仓储人员");
        return userId;
    }

    /// <summary>
    /// 获取物资仓储人员姓名
    /// </summary>
    private async Task<string?> GetWarehouseStaffName()
    {
        var (_, userName) = await GetUserByRoleNameAsync("物资仓储人员");
        return userName ?? "物资仓储人员"; // fallback到角色名称
    }

    /// <summary>
    /// 处理入库完成（物资仓储管理执行完成入库）
    /// </summary>
    private async Task HandleInboundCompletion(StoreProcessFlowStep entity)
    {
        // 更新入库申请记录状态
        await _storeInboundRep.AsUpdateable()
            .SetColumns(it => new StoreInbound
            {
                ApprovalAction = entity.ApprovalAction,
                CompletedTime = entity.CompletedTime
            })
            .Where(it => it.RequestNo == entity.RequestNo)
            .ExecuteCommandAsync();

        // 更新物资库存：从在途库存转为当前库存
        if (entity.MaterialId.HasValue && entity.Quantity.HasValue)
        {
            var affected = await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    CurrentStock = it.CurrentStock + entity.Quantity.Value,
                    AvailableStock = it.AvailableStock + entity.Quantity.Value,
                    InTransitStock = it.InTransitStock - entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value && it.InTransitStock >= entity.Quantity.Value)
                .ExecuteCommandAsync();

            if (affected == 0)
            {
                throw Oops.Oh("入库失败：在途库存不足，无法完成入库操作");
            }

            // 重新计算库存状态
            await UpdateStockStatus(entity.MaterialId.Value);
        }
    }

    /// <summary>
    /// 处理出库完成（物资仓储管理执行完成出库）
    /// </summary>
    private async Task HandleOutboundCompletion(StoreProcessFlowStep entity)
    {
        // 更新出库申请记录状态
        await _storeOutboundRep.AsUpdateable()
            .SetColumns(it => new StoreOutbound
            {
                ApprovalAction = entity.ApprovalAction,
                CompletedTime = entity.CompletedTime
            })
            .Where(it => it.RequestNo == entity.RequestNo)
            .ExecuteCommandAsync();

        // 更新物资库存：扣减预留库存和当前库存
        if (entity.MaterialId.HasValue && entity.Quantity.HasValue)
        {
            var affected = await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    CurrentStock = it.CurrentStock - entity.Quantity.Value,
                    ReservedStock = it.ReservedStock - entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value && it.ReservedStock >= entity.Quantity.Value && it.CurrentStock >= entity.Quantity.Value)
                .ExecuteCommandAsync();

            if (affected == 0)
            {
                throw Oops.Oh("出库失败：库存不足，无法完成发放");
            }

            // 重新计算库存状态
            await UpdateStockStatus(entity.MaterialId.Value);
        }
    }

    /// <summary>
    /// 创建流程记录
    /// </summary>
    private async Task CreateProcessRecord(StoreProcessFlowStep entity, StatusApprovalEnum originalStatus, bool adminDirectApprove = false, string? customRemark = null)
    {
        var currentTime = DateTime.Now;
        var processRecord = new StoreProcessRecord
        {
            FlowType = entity.FlowType,
            BatchNo = entity.BatchNo,
            RequestNo = entity.RequestNo,
            StoreTypeId = entity.StoreTypeId,
            StoreTypeName = entity.StoreTypeName,
            MaterialId = entity.MaterialId,
            MaterialName = entity.MaterialName,
            MaterialPrice = entity.MaterialPrice,
            Quantity = entity.Quantity,
            Unit = entity.Unit,
            MaterialPriceTotal = entity.MaterialPriceTotal,
            ApplicantId = entity.ApplicantId,
            ApplicantName = entity.ApplicantName,
            ApplicantDept = entity.ApplicantDept,
            ReceiverId = entity.ReceiverId,
            ReceiverName = entity.ReceiverName,
            ReceiverDept = entity.ReceiverDept,
            RequestTime = entity.RequestTime,
            ExpectedDate = entity.ExpectedDate,
            // 记录当前操作时间，而不是等到完全完成
            CompletedTime = currentTime,
            StatusNewOrChange = entity.StatusNewOrChange,
            Remark = customRemark ?? $"审批状态从 {GetStatusDisplayName(originalStatus)} 变更为 {GetStatusDisplayName(entity.ApprovalAction)}",
            ApprovalAction = entity.ApprovalAction,
            ConfirmerId = _userManager.UserId,
            ConfirmerName = _userManager.RealName,
        };

        if (adminDirectApprove)
        {
            processRecord.Remark = $"{processRecord.Remark}（系统管理员直接审批）";
        }

        await _storeProcessRecordRep.InsertAsync(processRecord);
    }

    private (int Step, StatusApprovalEnum Status) ResolvePreviousStep(StoreProcessFlowStep entity)
    {
        var definition = ResolveFlowDefinition(BuildFlowDefinitions(), entity.FlowType);
        var previous = definition.GetPreviousStage(entity.CurrentStep) ?? throw Oops.Oh("当前流程状态无法退回");
        return (previous.Step, previous.Status);
    }

    private async Task<(long? confirmerId, string? confirmerName)> ResolveReturnConfirmerAsync(StoreProcessFlowStep entity, StatusApprovalEnum targetStatus)
    {
        StoreProcessRecord? record = await _storeProcessRecordRep.AsQueryable()
            .Where(r => r.RequestNo == entity.RequestNo && r.ApprovalAction == targetStatus)
            .OrderBy(r => r.Id, OrderByType.Desc)
            .FirstAsync();

        if (record != null && record.ConfirmerId.HasValue)
        {
            return (record.ConfirmerId, record.ConfirmerName);
        }

        if (targetStatus == StatusApprovalEnum.Pending)
        {
            return (entity.ApplicantId, entity.ApplicantName);
        }

        return (entity.ConfirmerId, entity.ConfirmerName);
    }

    private async Task SyncRequestStatusAsync(StoreProcessFlowStep entity)
    {
        if (entity.FlowType == "入库")
        {
            await _storeInboundRep.AsUpdateable()
                .SetColumns(it => new StoreInbound
                {
                    ApprovalAction = entity.ApprovalAction,
                    CompletedTime = entity.CompletedTime,
                    ConfirmerId = entity.ConfirmerId,
                    ConfirmerName = entity.ConfirmerName
                })
                .Where(it => it.RequestNo == entity.RequestNo)
                .ExecuteCommandAsync();
        }
        else if (entity.FlowType == "出库")
        {
            await _storeOutboundRep.AsUpdateable()
                .SetColumns(it => new StoreOutbound
                {
                    ApprovalAction = entity.ApprovalAction,
                    CompletedTime = entity.CompletedTime,
                    ConfirmerId = entity.ConfirmerId,
                    ConfirmerName = entity.ConfirmerName
                })
                .Where(it => it.RequestNo == entity.RequestNo)
                .ExecuteCommandAsync();
        }
    }

    private static string BuildReturnRemark(StatusApprovalEnum originalStatus, StatusApprovalEnum targetStatus, string? reason)
    {
        var remark = $"审批状态从 {GetStatusDisplayName(originalStatus)} 退回至 {GetStatusDisplayName(targetStatus)}";
        if (!string.IsNullOrWhiteSpace(reason))
        {
            remark = $"{remark}，原因：{reason!.Trim()}";
        }

        return remark;
    }

    private async Task<bool> IsSystemAdminAsync(long userId)
    {
        var accountType = await _sysUserRep.AsQueryable()
            .ClearFilter()
            .Where(u => u.Id == userId)
            .Select(u => u.AccountType)
            .FirstAsync();

        return accountType == AccountTypeEnum.SysAdmin || accountType == AccountTypeEnum.SuperAdmin;
    }


    /// <summary>
    /// 处理审批完成后的业务逻辑
    /// </summary>
    private async Task HandleApprovalCompletion(StoreProcessFlowStep entity)
    {
        // 根据流程类型处理不同的业务逻辑
        if (entity.FlowType == "入库")
        {
            await HandleInboundApprovalCompletion(entity);
        }
        else if (entity.FlowType == "出库")
        {
            await HandleOutboundApprovalCompletion(entity);
        }
    }

    /// <summary>
    /// 处理入库审批完成
    /// </summary>
    private async Task HandleInboundApprovalCompletion(StoreProcessFlowStep entity)
    {
        // 更新入库申请记录状态
        await _storeInboundRep.AsUpdateable()
            .SetColumns(it => new StoreInbound
            {
                ApprovalAction = entity.ApprovalAction,
                CompletedTime = entity.CompletedTime
            })
            .Where(it => it.RequestNo == entity.RequestNo)
            .ExecuteCommandAsync();

        // 更新物资库存：从在途库存转为当前库存
        if (entity.MaterialId.HasValue && entity.Quantity.HasValue)
        {
            await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    CurrentStock = it.CurrentStock + entity.Quantity.Value,
                    AvailableStock = it.AvailableStock + entity.Quantity.Value,
                    InTransitStock = it.InTransitStock - entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value)
                .ExecuteCommandAsync();

            // 重新计算库存状态
            await UpdateStockStatus(entity.MaterialId.Value);
        }
    }

    /// <summary>
    /// 处理出库审批完成
    /// </summary>
    private async Task HandleOutboundApprovalCompletion(StoreProcessFlowStep entity)
    {
        // 更新出库申请记录状态
        await _storeOutboundRep.AsUpdateable()
            .SetColumns(it => new StoreOutbound
            {
                ApprovalAction = entity.ApprovalAction,
                CompletedTime = entity.CompletedTime
            })
            .Where(it => it.RequestNo == entity.RequestNo)
            .ExecuteCommandAsync();

        // 更新物资库存：扣减当前库存和可用库存
        if (entity.MaterialId.HasValue && entity.Quantity.HasValue)
        {
            var affected = await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    CurrentStock = it.CurrentStock - entity.Quantity.Value,
                    AvailableStock = it.AvailableStock - entity.Quantity.Value,
                    ReservedStock = it.ReservedStock - entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value && it.AvailableStock >= entity.Quantity.Value && it.ReservedStock >= entity.Quantity.Value)
                .ExecuteCommandAsync();

            if (affected == 0)
            {
                throw Oops.Oh("出库失败：可用库存或预留库存不足，无法完成发放");
            }

            // 重新计算库存状态
            await UpdateStockStatus(entity.MaterialId.Value);
        }
    }

    /// <summary>
    /// 更新库存状态
    /// </summary>
    private async Task UpdateStockStatus(long materialId)
    {
        var material = await _storeMaterialsRep.GetFirstAsync(it => it.Id == materialId);
        if (material != null)
        {
            var newStatus = StockStatusEnum.Normal;
            
            if (material.CurrentStock <= 0)
            {
                newStatus = StockStatusEnum.OutOfStock; // 缺货
            }
            else if (material.MinStock.HasValue && material.CurrentStock <= material.MinStock.Value)
            {
                newStatus = StockStatusEnum.Warning; // 预警
            }

            if (material.StockStatus != newStatus)
            {
                await _storeMaterialsRep.AsUpdateable()
                    .SetColumns(it => new StoreMaterials { StockStatus = newStatus })
                    .Where(it => it.Id == materialId)
                    .ExecuteCommandAsync();
            }
        }
    }

    /// <summary>
    /// 获取状态显示名称
    /// </summary>
    private static string GetStatusDisplayName(StatusApprovalEnum status)
    {
        return status switch
        {
            StatusApprovalEnum.Pending => "待审核",
            StatusApprovalEnum.Reviewed => "已审核",
            StatusApprovalEnum.Approved => "已批准",
            StatusApprovalEnum.Rejected => "已拒绝",
            StatusApprovalEnum.Completed => "已完成",
            _ => status.ToString()
        };
    }

    /// <summary>
    /// 删除审批流程 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除审批流程")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteStoreProcessFlowStepInput input)
    {
        // 使用事务确保数据一致性
        await _sqlSugarClient.Ado.UseTranAsync(async () =>
        {
            var entity = await _storeProcessFlowStepRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);

            // 如果是已完成的操作，需要还原库存
            if (entity.CompletedTime != null && entity.ApprovalAction == StatusApprovalEnum.Completed)
            {
                // 还原库存操作
                if (entity.FlowType == "入库")
                {
                    await ReverseInboundOperation(entity);
                }
                else if (entity.FlowType == "出库")
                {
                    await ReverseOutboundOperation(entity);
                }

                // 更新对应的入库出库记录状态
                if (entity.FlowType == "入库")
                {
                    await _storeInboundRep.AsUpdateable()
                        .SetColumns(it => new StoreInbound
                        {
                            ApprovalAction = StatusApprovalEnum.Rejected,
                            CompletedTime = null
                        })
                        .Where(it => it.RequestNo == entity.RequestNo)
                        .ExecuteCommandAsync();
                }
                else if (entity.FlowType == "出库")
                {
                    await _storeOutboundRep.AsUpdateable()
                        .SetColumns(it => new StoreOutbound
                        {
                            ApprovalAction = StatusApprovalEnum.Rejected,
                            CompletedTime = null
                        })
                        .Where(it => it.RequestNo == entity.RequestNo)
                        .ExecuteCommandAsync();
                }

                // 创建删除撤回记录
                await CreateDeleteWithdrawRecord(entity, "删除审批流程时自动撤回库存操作");
            }

            await _storeProcessFlowStepRep.FakeDeleteAsync(entity);   //假删除
        });
    }

    /// <summary>
    /// 批量删除审批流程 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除审批流程")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteStoreProcessFlowStepInput> input)
    {
        var exp = Expressionable.Create<StoreProcessFlowStep>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _storeProcessFlowStepRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        return await _storeProcessFlowStepRep.FakeDeleteAsync(list);   //假删除
        //return await _storeProcessFlowStepRep.DeleteAsync(list);   //真删除
    }


    /// <summary>
    /// 撤回入库操作：将库存从当前库存转回在途库存
    /// </summary>
    private async Task ReverseInboundOperation(StoreProcessFlowStep entity)
    {
        if (entity.MaterialId.HasValue && entity.Quantity.HasValue)
        {
            await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    CurrentStock = it.CurrentStock - entity.Quantity.Value,
                    AvailableStock = it.AvailableStock - entity.Quantity.Value,
                    InTransitStock = it.InTransitStock + entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value)
                .ExecuteCommandAsync();

            // 重新计算库存状态
            await UpdateStockStatus(entity.MaterialId.Value);
        }
    }

    /// <summary>
    /// 撤回出库操作：将库存加回当前库存和可用库存
    /// </summary>
    private async Task ReverseOutboundOperation(StoreProcessFlowStep entity)
    {
        if (entity.MaterialId.HasValue && entity.Quantity.HasValue)
        {
            await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    CurrentStock = it.CurrentStock + entity.Quantity.Value,
                    AvailableStock = it.AvailableStock + entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value)
                .ExecuteCommandAsync();

            // 重新计算库存状态
            await UpdateStockStatus(entity.MaterialId.Value);
        }
    }

    /// <summary>
    /// 处理拒绝审批时的库存回滚
    /// </summary>
    private async Task HandleRejectionInventoryRollback(StoreProcessFlowStep entity)
    {
        if (!entity.MaterialId.HasValue || !entity.Quantity.HasValue)
            return;

        var isInbound = entity.FlowType == "入库";
        var isOutbound = entity.FlowType == "出库";

        if (isInbound)
        {
            // 入库被拒绝：回滚在途库存 (InTransitStock -= quantity)
            await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    InTransitStock = it.InTransitStock - entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value)
                .ExecuteCommandAsync();
        }
        else if (isOutbound)
        {
            // 出库被拒绝：回滚预留库存和可用库存 (ReservedStock -= quantity, AvailableStock += quantity)
            await _storeMaterialsRep.AsUpdateable()
                .SetColumns(it => new StoreMaterials
                {
                    ReservedStock = it.ReservedStock - entity.Quantity.Value,
                    AvailableStock = it.AvailableStock + entity.Quantity.Value,
                    LastStockUpdateTime = DateTime.Now
                })
                .Where(it => it.Id == entity.MaterialId.Value)
                .ExecuteCommandAsync();
        }

        // 重新计算库存状态
        await UpdateStockStatus(entity.MaterialId.Value);

        // 更新原始申请记录状态为拒绝
        if (isInbound)
        {
            await _storeInboundRep.AsUpdateable()
                .SetColumns(it => new StoreInbound
                {
                    ApprovalAction = StatusApprovalEnum.Rejected,
                    CompletedTime = DateTime.Now
                })
                .Where(it => it.RequestNo == entity.RequestNo)
                .ExecuteCommandAsync();
        }
        else if (isOutbound)
        {
            await _storeOutboundRep.AsUpdateable()
                .SetColumns(it => new StoreOutbound
                {
                    ApprovalAction = StatusApprovalEnum.Rejected,
                    CompletedTime = DateTime.Now
                })
                .Where(it => it.RequestNo == entity.RequestNo)
                .ExecuteCommandAsync();
        }
    }

    /// <summary>
    /// 创建撤回记录
    /// </summary>
    private async Task CreateWithdrawRecord(StoreProcessFlowStep entity, string? reason)
    {
        var currentTime = DateTime.Now;
        var processRecord = new StoreProcessRecord
        {
            FlowType = entity.FlowType,
            BatchNo = entity.BatchNo,
            RequestNo = entity.RequestNo,
            StoreTypeId = entity.StoreTypeId,
            StoreTypeName = entity.StoreTypeName,
            MaterialId = entity.MaterialId,
            MaterialName = entity.MaterialName,
            MaterialPrice = entity.MaterialPrice,
            Quantity = entity.Quantity,
            Unit = entity.Unit,
            MaterialPriceTotal = entity.MaterialPriceTotal,
            ApplicantId = entity.ApplicantId,
            ApplicantName = entity.ApplicantName,
            ApplicantDept = entity.ApplicantDept,
            ReceiverId = entity.ReceiverId,
            ReceiverName = entity.ReceiverName,
            ReceiverDept = entity.ReceiverDept,
            RequestTime = entity.RequestTime,
            ExpectedDate = entity.ExpectedDate,
            CompletedTime = currentTime,
            StatusNewOrChange = entity.StatusNewOrChange,
            Remark = $"撤回已完成的{entity.FlowType}操作：{reason ?? "管理员撤回"}",
            ApprovalAction = StatusApprovalEnum.Rejected,
            ConfirmerId = entity.ConfirmerId,
            ConfirmerName = entity.ConfirmerName
        };

        await _storeProcessRecordRep.InsertAsync(processRecord);
    }

    /// <summary>
    /// 创建删除撤回记录
    /// </summary>
    private async Task CreateDeleteWithdrawRecord(StoreProcessFlowStep entity, string? reason)
    {
        var currentTime = DateTime.Now;
        var processRecord = new StoreProcessRecord
        {
            FlowType = entity.FlowType,
            BatchNo = entity.BatchNo,
            RequestNo = entity.RequestNo,
            StoreTypeId = entity.StoreTypeId,
            StoreTypeName = entity.StoreTypeName,
            MaterialId = entity.MaterialId,
            MaterialName = entity.MaterialName,
            MaterialPrice = entity.MaterialPrice,
            Quantity = entity.Quantity,
            Unit = entity.Unit,
            MaterialPriceTotal = entity.MaterialPriceTotal,
            ApplicantId = entity.ApplicantId,
            ApplicantName = entity.ApplicantName,
            ApplicantDept = entity.ApplicantDept,
            ReceiverId = entity.ReceiverId,
            ReceiverName = entity.ReceiverName,
            ReceiverDept = entity.ReceiverDept,
            RequestTime = entity.RequestTime,
            ExpectedDate = entity.ExpectedDate,
            CompletedTime = currentTime,
            StatusNewOrChange = entity.StatusNewOrChange,
            Remark = $"删除审批流程时自动撤回{entity.FlowType}操作：{reason ?? "删除操作自动撤回库存"}",
            ApprovalAction = StatusApprovalEnum.Rejected,
            ConfirmerId = entity.ConfirmerId,
            ConfirmerName = entity.ConfirmerName
        };

        await _storeProcessRecordRep.InsertAsync(processRecord);
    }

    /// <summary>
    /// 获取指定分类及其所有下级分类的ID列表
    /// </summary>
    /// <param name="categoryId">分类ID</param>
    /// <returns>包含指定分类及其所有下级分类的ID列表</returns>
    /// <summary>
    /// 获取机构及其所有下级机构的ID列表
    /// </summary>
    /// <param name="orgId">机构ID</param>
    /// <returns>机构ID列表</returns>
    private async Task<List<long>> GetOrgAndChildrenIds(long orgId)
    {
        var orgTableName = _sqlSugarClient.EntityMaintenance.GetTableName<SysOrg>();
        if (!_sqlSugarClient.DbMaintenance.IsAnyTable(orgTableName))
        {
            return new List<long> { orgId };
        }

        var allNodes = await _sqlSugarClient.Queryable<SysOrg>()
            .ClearFilter()
            .Select(x => new { x.Id, x.Pid })
            .ToListAsync();

        if (allNodes == null || allNodes.Count == 0)
        {
            return new List<long> { orgId };
        }

        var childrenLookup = allNodes
            .GroupBy(x => x.Pid)
            .ToDictionary(g => g.Key, g => g.Select(item => item.Id).ToList());

        var result = new HashSet<long> { orgId };
        var queue = new Queue<long>();
        queue.Enqueue(orgId);

        while (queue.Count > 0)
        {
            var current = queue.Dequeue();
            if (!childrenLookup.TryGetValue(current, out var children))
            {
                continue;
            }

            foreach (var childId in children)
            {
                if (result.Add(childId))
                {
                    queue.Enqueue(childId);
                }
            }
        }

        return result.ToList();
    }

    private async Task<List<long>> GetCategoryAndChildrenIds(long categoryId)
    {
        var categoryTableName = _sqlSugarClient.EntityMaintenance.GetTableName<StoreType>();
        if (!_sqlSugarClient.DbMaintenance.IsAnyTable(categoryTableName))
        {
            return new List<long> { categoryId };
        }

        var allCategories = await _sqlSugarClient.Queryable<StoreType>()
            .Where(x => x.Status == StatusEnum.Enable)
            .Select(x => new { x.Id, x.Pid })
            .ToListAsync();

        if (allCategories == null || allCategories.Count == 0)
        {
            return new List<long> { categoryId };
        }

        var childrenLookup = allCategories
            .Where(x => x.Pid.HasValue)
            .GroupBy(x => x.Pid!.Value)
            .ToDictionary(g => g.Key, g => g.Select(item => item.Id).ToList());

        var result = new HashSet<long> { categoryId };
        var queue = new Queue<long>();
        queue.Enqueue(categoryId);

        while (queue.Count > 0)
        {
            var current = queue.Dequeue();
            if (!childrenLookup.TryGetValue(current, out var children))
            {
                continue;
            }

            foreach (var childId in children)
            {
                if (result.Add(childId))
                {
                    queue.Enqueue(childId);
                }
            }
        }

        return result.ToList();
    }

    /// <summary>
    /// 执行阶段默认当前操作人为确认人
    /// </summary>
    private void AssignExecutionConfirmer(StoreProcessFlowStep entity)
    {
        entity.ConfirmerId = _userManager.UserId;
        entity.ConfirmerName = _userManager.RealName;
    }

    /// <summary>
    /// 自动分配默认确认人（直属主管或当前用户）
    /// </summary>
    private async Task AssignDefaultConfirmer(StoreProcessFlowStep entity)
    {
        var targetUserId = _userManager.UserId;
        var currentUser = await _sysUserRep.AsQueryable()
            .ClearFilter()
            .Where(x => x.Id == targetUserId).FirstAsync();
        if (currentUser?.ManagerUserId != null)
        {
            // 先查询主管基本信息
            var managerUser = await _sysUserRep.AsQueryable()
                .ClearFilter()
                .Where(u => u.Id == currentUser.ManagerUserId.Value && u.Status == StatusEnum.Enable)
                .FirstAsync();
            if (managerUser != null)
            {
                entity.ConfirmerId = managerUser.Id;
                entity.ConfirmerName = managerUser.RealName;
            }
            else
            {
                entity.ConfirmerId = _userManager.UserId;
                entity.ConfirmerName = _userManager.RealName;
            }
        }
        else
        {
            entity.ConfirmerId = _userManager.UserId;
            entity.ConfirmerName = _userManager.RealName;
        }
    }

    /// <summary>
    /// 导出审批流程 📊
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出审批流程")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageStoreProcessFlowStepInput input)
    {
        var pageResult = await Page(input);
        var list = pageResult.Items?.Adapt<List<ExportStoreProcessFlowStepOutput>>() ?? new();

        if (input.SelectKeyList?.Count > 0)
            list = list.Where(x => input.SelectKeyList.Contains(x.Id.ToString())).ToList();

        // 获取所有涉及的OrgId，用来构建完整的组织路径
        var orgIds = list.Where(x => x.OrgId.HasValue).Select(x => x.OrgId.Value).Distinct().ToList();
        Dictionary<long, string> orgPaths = new();

        foreach (var orgId in orgIds)
        {
            var path = await BuildOrgPathAsync(orgId);
            orgPaths[orgId] = path;
        }

        // 获取接收人的OrgId
        var receiverIds = list.Where(x => x.ReceiverId.HasValue).Select(x => x.ReceiverId.Value).Distinct().ToList();
        Dictionary<long, long?> receiverOrgMap = new();

        foreach (var receiverId in receiverIds)
        {
            var user = await _sqlSugarClient.Queryable<SysUser>()
                .ClearFilter()
                .Where(x => x.Id == receiverId)
                .Select(x => new { x.Id, x.OrgId })
                .FirstAsync();

            if (user != null)
            {
                receiverOrgMap[receiverId] = user.OrgId;
            }
        }

        // 填充区域完整路径
        foreach (var item in list)
        {
            // 申请人区域
            if (item.OrgId.HasValue && orgPaths.ContainsKey(item.OrgId.Value))
            {
                item.ApplicantDeptPath = orgPaths[item.OrgId.Value];
            }

            // 接收人区域
            if (item.ReceiverId.HasValue && receiverOrgMap.ContainsKey(item.ReceiverId.Value))
            {
                var receiverOrgId = receiverOrgMap[item.ReceiverId.Value];
                if (receiverOrgId.HasValue)
                {
                    // 如果还没有构建过这个OrgId的路径，就构建一次
                    if (!orgPaths.ContainsKey(receiverOrgId.Value))
                    {
                        var path = await BuildOrgPathAsync(receiverOrgId.Value);
                        orgPaths[receiverOrgId.Value] = path;
                    }
                    item.ReceiverDeptPath = orgPaths[receiverOrgId.Value];
                }
            }
        }

        return ExcelHelper.ExportTemplate(list, "审批流程导出");
    }

    /// <summary>
    /// 构建组织路径
    /// </summary>
    private async Task<string> BuildOrgPathAsync(long orgId)
    {
        var path = new List<string>();
        var currentId = orgId;

        while (currentId > 0)
        {
            var org = await _sqlSugarClient.Queryable<SysOrg>()
                .ClearFilter()
                .Where(x => x.Id == currentId)
                .FirstAsync();

            if (org == null) break;

            path.Insert(0, org.Name);

            // Pid是long类型，直接比较
            if (org.Pid <= 0)
                break;

            currentId = org.Pid;
        }

        return string.Join("/", path);
    }

    private void PopulateFlowRuntimeMetadata(StoreProcessFlowStepOutput item, long loginUserId, bool isSystemAdmin, bool canManageAllSteps, Dictionary<string, FlowDefinition> flowDefinitions)
    {
        var definition = ResolveFlowDefinition(flowDefinitions, item.FlowType);
        var stage = definition.GetStage(item.CurrentStep);
        var nextStage = definition.GetNextStage(item.CurrentStep);
        var previousStage = definition.GetPreviousStage(item.CurrentStep);
        var isCurrentUserConfirmer = item.ConfirmerId == loginUserId;
        var userCanOperate = canManageAllSteps || isCurrentUserConfirmer;
        var isClosed = item.ApprovalAction is StatusApprovalEnum.Completed or StatusApprovalEnum.Rejected;

        item.CurrentStageName = stage.DisplayName;
        item.NextStageName = nextStage?.DisplayName;
        item.NextApprovalAction = nextStage?.Status;
        item.StageRequiresConfirmer = stage.RequiresConfirmer;
        item.IsExecutionStage = stage.IsExecutionStage;
        item.CanAdminDirectApprove = isSystemAdmin
            && definition.SupportsAdminDirectApprove
            && definition.DirectApprovalStep.HasValue
            && stage.Step < definition.DirectApprovalStep.Value;
        item.CanApprove = userCanOperate && !isClosed && nextStage != null;
        item.CanReject = userCanOperate && !isClosed;
        item.CanReturn = userCanOperate && previousStage != null && !isClosed;
    }

    private async Task<HashSet<string>> GetUserRoleCodesAsync(long userId)
    {
        var codes = await _sysUserRoleRep.AsQueryable()
            .InnerJoin<SysRole>((ur, role) => ur.RoleId == role.Id)
            .Where((ur, role) => ur.UserId == userId && role.Status == StatusEnum.Enable)
            .Select((ur, role) => role.Code)
            .ToListAsync();

        return codes
            .Where(code => !string.IsNullOrWhiteSpace(code))
            .Select(code => code!)
            .ToHashSet(StringComparer.OrdinalIgnoreCase);
    }

    private static Dictionary<string, FlowDefinition> BuildFlowDefinitions()
    {
        return new Dictionary<string, FlowDefinition>(StringComparer.OrdinalIgnoreCase)
        {
            ["入库"] = FlowDefinition.CreateInbound(),
            ["出库"] = FlowDefinition.CreateOutbound()
        };
    }

    private static FlowDefinition ResolveFlowDefinition(Dictionary<string, FlowDefinition> definitions, string? flowType)
    {
        if (!string.IsNullOrWhiteSpace(flowType) && definitions.TryGetValue(flowType, out var definition))
        {
            return definition;
        }

        return definitions["入库"];
    }

    private static class RoleCodes
    {
        public const string StoreManager = "store_manager";
    }

    private sealed class FlowDefinition
    {
        private readonly IReadOnlyList<FlowStage> _stages;

        private FlowDefinition(string flowType, IEnumerable<FlowStage> stages, int? directApprovalStep)
        {
            FlowType = flowType;
            _stages = stages.OrderBy(stage => stage.Step).ToList();
            DirectApprovalStep = directApprovalStep;
        }

        public string FlowType { get; }

        public int TotalSteps => _stages.Count;

        public bool SupportsAdminDirectApprove => DirectApprovalStep.HasValue;

        public int? DirectApprovalStep { get; }

        public FlowStage GetStage(int step)
        {
            var index = Math.Clamp(step - 1, 0, _stages.Count - 1);
            return _stages[index];
        }

        public FlowStage? GetNextStage(int currentStep, bool adminDirectApprove = false)
        {
            if (adminDirectApprove && DirectApprovalStep.HasValue && currentStep < DirectApprovalStep.Value)
            {
                return GetStage(DirectApprovalStep.Value);
            }

            var nextIndex = currentStep;
            if (nextIndex >= _stages.Count)
            {
                return null;
            }

            return _stages[nextIndex];
        }

        public FlowStage? GetPreviousStage(int currentStep)
        {
            var previousIndex = currentStep - 2;
            if (previousIndex < 0)
            {
                return null;
            }

            return previousIndex < _stages.Count ? _stages[previousIndex] : _stages.LastOrDefault();
        }

        public FlowStage GetFinalStage() => _stages[^1];

        public static FlowDefinition CreateInbound()
        {
            return new FlowDefinition("入库", new[]
            {
                new FlowStage(1, StatusApprovalEnum.Pending, "部门审批", false, false, false),
                new FlowStage(2, StatusApprovalEnum.Approved, "仓储确认", true, true, false),
                new FlowStage(3, StatusApprovalEnum.Completed, "入库完成", false, true, true)
            }, null);
        }

        public static FlowDefinition CreateOutbound()
        {
            return new FlowDefinition("出库", new[]
            {
                new FlowStage(1, StatusApprovalEnum.Pending, "部门审核", false, false, false),
                new FlowStage(2, StatusApprovalEnum.Reviewed, "仓储审批", true, false, false),
                new FlowStage(3, StatusApprovalEnum.Approved, "仓储发放", true, true, false),
                new FlowStage(4, StatusApprovalEnum.Completed, "出库完成", false, true, true)
            }, directApprovalStep: 3);
        }
    }

    private sealed record FlowStage(int Step, StatusApprovalEnum Status, string DisplayName, bool RequiresConfirmer, bool IsExecutionStage, bool IsCompletion);

    /// <summary>
    /// 获取物资分类下拉列表数据 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取物资分类下拉列表数据")]
    [ApiDescriptionSettings(Name = "GetStoreTypeDropdownData"), HttpPost]
    public async Task<Dictionary<string, dynamic>> GetStoreTypeDropdownData(DropdownDataStoreTypeInput input)
    {
        return await _storeMaterialsService.DropdownData(input);
    }
}
